﻿using Cinch;
using FR.SAFTAnalyserLite.Model;
using FR.SAFTAnalyserLite.ViewModels.Pane;
using MEFedMVVM.Common;
using OfficeOpenXml;
using OfficeOpenXml.Table;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FR.SAFTAnalyserLite.ViewModels
{
    public class WorkingDocumentsViewModel : DocumentPartViewModel
    {
        public WorkingDocumentsViewModel()
            : base("Documentos de conferência")
        {
            if (!Designer.IsInDesignMode)
            {
                Mediator.Instance.Register(this);

                DoOpenExcelCommand = new SimpleCommand<object, object>(CanOpenExcel, OpenExcel);
                ShowCustomerCommand = new SimpleCommand<object, object>(CanShowCustomer, DoShowCustomer);
                TestHashCommand = new SimpleCommand<object, object>(CanTestHash, DoTestHash);

                this.filtroDataInicio = DateTime.MinValue;
                this.FiltroDataFim = DateTime.MaxValue;
            }
        }

        internal override void ResetSaftFile()
        {
            this.WorkingDocuments = null;
            this.WorkDocument = null;
            this.CurrentWorkDocument = null;
            this.CurrentWorkDocumentLines = null;
            this.CurrentWorkDocumentLine = null;
        }

        #region Mediator messages
        [MediatorMessageSink(MessageType.SAFT_FILE_OPENED)]
        private void Load(AuditFile saft)
        {
            if (saft != null && saft.SourceDocuments != null && saft.SourceDocuments.WorkingDocuments != null)
                this.WorkingDocuments = saft.SourceDocuments.WorkingDocuments;
        }

        [MediatorMessageSink(MessageType.INVOICE_LIST_CHANGED)]
        private void Reload(AuditFile saft)
        {
            if (saft != null && saft.SourceDocuments != null && saft.SourceDocuments.WorkingDocuments != null)
                this.WorkingDocuments = saft.SourceDocuments.WorkingDocuments;
        }
        #endregion

        #region Binding properties
        SourceDocumentsWorkingDocuments workingDocuments;
        public SourceDocumentsWorkingDocuments WorkingDocuments
        {
            get
            {
                if (workingDocuments == null && SAFT.SaftAnalyser.Instance.SaftFile != null && SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments != null)
                    workingDocuments = SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.WorkingDocuments;

                return workingDocuments;
            }
            set
            {
                workingDocuments = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.WorkingDocuments));

                if (workingDocuments != null && string.IsNullOrEmpty(this.FilterWorkDocument))
                {
                    DocNumberOfEntries = workingDocuments.WorkDocument.Length;
                    DocTotalCredit = workingDocuments.WorkDocument
                                             .Where(c => c.DocumentStatus.WorkStatus != WorkStatus.A)
                                             .Sum(c => c.Line.Sum(l => l.ItemElementName == ItemChoiceType8.CreditAmount ? l.Item : 0))
                                             .ToString("c");

                    DocTotalDebit = workingDocuments.WorkDocument
                                            .Where(c => c.DocumentStatus.WorkStatus != WorkStatus.A)
                                            .Sum(c => c.Line.Sum(l => l.ItemElementName == ItemChoiceType8.DebitAmount ? l.Item : 0))
                                            .ToString("c");

                    NumberOfEntries = workingDocuments.NumberOfEntries;
                    TotalCredit = workingDocuments.TotalCredit.ToString("c");
                    TotalDebit = workingDocuments.TotalDebit.ToString("c");

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocNumberOfEntries));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocTotalCredit));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocTotalDebit));

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.NumberOfEntries));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.TotalCredit));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.TotalDebit));

                    this.filtroDataInicio = workingDocuments.WorkDocument.Min(i => i.WorkDate);
                    this.filtroDataFim = workingDocuments.WorkDocument.Max(i => i.WorkDate);

                    this.WorkDocument = workingDocuments.WorkDocument;
                }
            }
        }

        SourceDocumentsWorkingDocumentsWorkDocument[] workDocument;
        public SourceDocumentsWorkingDocumentsWorkDocument[] WorkDocument
        {
            get { return workDocument; }
            set
            {
                workDocument = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.WorkDocument));
            }
        }

        SourceDocumentsWorkingDocumentsWorkDocument currentWorkDocument;
        public SourceDocumentsWorkingDocumentsWorkDocument CurrentWorkDocument
        {
            get { return currentWorkDocument; }
            set
            {
                currentWorkDocument = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.CurrentWorkDocument));

                if (currentWorkDocument != null)
                {
                    DocGrossTotal = currentWorkDocument.Line.Sum(c => c.Item * (1 + c.Tax.Item * 0.01m)).ToString("c");
                    DocNetTotal = currentWorkDocument.Line.Sum(c => c.Item).ToString("c");
                    DocTaxPayable = currentWorkDocument.Line.Sum(c => c.Item * c.Tax.Item * 0.01m).ToString("c");

                    GrossTotal = currentWorkDocument.DocumentTotals.GrossTotal.ToString("c");
                    NetTotal = currentWorkDocument.DocumentTotals.NetTotal.ToString("c");
                    TaxPayable = currentWorkDocument.DocumentTotals.TaxPayable.ToString("c");

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocGrossTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocNetTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.DocTaxPayable));

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.GrossTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.NetTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.TaxPayable));

                    if (string.IsNullOrEmpty(this.FilterLines) && !this.ShowAllLines)
                        this.CurrentWorkDocumentLines = currentWorkDocument.Line;
                }
            }
        }

        SourceDocumentsWorkingDocumentsWorkDocumentLine[] currentWorkDocumentLines;
        public SourceDocumentsWorkingDocumentsWorkDocumentLine[] CurrentWorkDocumentLines
        {
            get { return currentWorkDocumentLines; }
            set
            {
                currentWorkDocumentLines = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.CurrentWorkDocumentLines));
            }
        }

        SourceDocumentsWorkingDocumentsWorkDocumentLine currentWorkDocumentLine;
        public SourceDocumentsWorkingDocumentsWorkDocumentLine CurrentWorkDocumentLine
        {
            get { return currentWorkDocumentLine; }
            set
            {
                currentWorkDocumentLine = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.CurrentWorkDocumentLine));
            }
        }

        bool showAllLines;
        public bool ShowAllLines
        {
            get { return showAllLines; }
            set
            {
                showAllLines = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.ShowAllLines));

                if (showAllLines)
                    this.CurrentWorkDocumentLines = WorkDocument.SelectMany(i => i.Line).ToArray();
                else
                    this.CurrentWorkDocumentLines = CurrentWorkDocument.Line;
            }
        }

        DateTime filtroDataInicio;
        public DateTime FiltroDataInicio
        {
            get { return filtroDataInicio; }
            set
            {
                filtroDataInicio = value;
                FilterWorkingDocumentByDate();
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.FiltroDataInicio));
            }
        }
        DateTime filtroDataFim;
        public DateTime FiltroDataFim
        {
            get { return filtroDataFim; }
            set
            {
                filtroDataFim = value;
                FilterWorkingDocumentByDate();
                NotifyPropertyChanged(ObservableHelper.CreateArgs<WorkingDocumentsViewModel>(x => x.FiltroDataFim));
            }
        }

        private void FilterWorkingDocumentByDate()
        {
            if (SAFT.SaftAnalyser.Instance.SaftFile != null && SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.WorkingDocuments != null)
            {
                var inv = from i in SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.WorkingDocuments.WorkDocument
                          where i.WorkDate >= filtroDataInicio && i.WorkDate <= FiltroDataFim
                          select i;

                this.WorkDocument = inv.ToArray();
            }
        }

        string filterWorkDocument;
        public string FilterWorkDocument
        {
            get { return filterWorkDocument; }
            set
            {
                filterWorkDocument = value;

                if (string.IsNullOrEmpty(filterWorkDocument))
                    this.WorkDocument = SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.WorkingDocuments.WorkDocument;
                else
                {
                    var inv = from i in SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.WorkingDocuments.WorkDocument
                              where i.DocumentNumber.IndexOf(filterWorkDocument, StringComparison.OrdinalIgnoreCase) >= 0 ||
                              i.CustomerID.IndexOf(filterWorkDocument, StringComparison.OrdinalIgnoreCase) >= 0
                              select i;

                    this.WorkDocument = inv.ToArray();
                }
            }
        }

        string filterLines;
        public string FilterLines
        {
            get { return filterLines; }
            set
            {
                filterLines = value;

                if (string.IsNullOrEmpty(filterLines))
                    this.CurrentWorkDocumentLines = this.CurrentWorkDocument.Line;
                else
                {
                    var lines = from l in this.CurrentWorkDocument.Line
                                where l.ProductDescription.IndexOf(filterLines, StringComparison.OrdinalIgnoreCase) >= 0 ||
                                        l.ProductCode.IndexOf(filterLines, StringComparison.OrdinalIgnoreCase) >= 0 ||
                                        l.Description.IndexOf(filterLines, StringComparison.OrdinalIgnoreCase) >= 0
                                select l;

                    this.CurrentWorkDocumentLines = lines.ToArray();
                }
            }
        }

        public string DocGrossTotal { get; set; }
        public string DocNetTotal { get; set; }
        public string DocTaxPayable { get; set; }
        public int DocNumberOfEntries { get; set; }
        public string DocTotalCredit { get; set; }
        public string DocTotalDebit { get; set; }

        public string GrossTotal { get; set; }
        public string NetTotal { get; set; }
        public string TaxPayable { get; set; }
        public string NumberOfEntries { get; set; }
        public string TotalCredit { get; set; }
        public string TotalDebit { get; set; }
        #endregion

        #region Commands
        public SimpleCommand<object, object> TestHashCommand { get; set; }
        private void DoTestHash(object obj)
        {
            string hashDocumentoAnterior = null;

            //fazer parse do campo InvoiceNo, descobrir o nº do documento actual e obter o documento anterior
            string[] docNo = this.CurrentWorkDocument.DocumentNumber.Split('/');
            if (docNo != null && docNo.Length == 2)
            {
                int num = 0;
                Int32.TryParse(docNo[1], out num);
                num = num - 1;

                if (num > 0)
                {
                    SourceDocumentsWorkingDocumentsWorkDocument doc
                        = this.WorkDocument.Where(i => i.DocumentNumber.IndexOf(string.Format("{0}/{1}", docNo[0], num), StringComparison.OrdinalIgnoreCase) == 0).FirstOrDefault();

                    //encontramos um documento, vamos obter a hash
                    if (doc != null)
                        hashDocumentoAnterior = doc.Hash;
                }
            }

            Workspace.Workspace.Instance.ShowCreateHashTool(this.CurrentWorkDocument, hashDocumentoAnterior);
        }
        private bool CanTestHash(object arg)
        {
            return this.CurrentWorkDocument != null;
        }

        public SimpleCommand<object, object> DoOpenExcelCommand { get; private set; }
        private void OpenExcel(object args)
        {
            OpenMovementInExcel(this.CurrentWorkDocument, this.ShowAllLines ? this.WorkingDocuments.WorkDocument.SelectMany(w => w.Line).ToArray() : this.CurrentWorkDocumentLines);
        }
        private bool CanOpenExcel(object args)
        {
            if (this.CurrentWorkDocument != null && this.CurrentWorkDocument.Line != null && this.WorkingDocuments != null)
                return true;
            else
                return false;
        }

        public SimpleCommand<object, object> ShowCustomerCommand { get; private set; }
        private void DoShowCustomer(object args)
        {
            Workspace.Workspace.Instance.ShowCustomer(this.CurrentWorkDocument.Pk);
        }
        private bool CanShowCustomer(object args)
        {
            return this.CurrentWorkDocument != null;
        }
        #endregion

        private int Operation(SourceDocumentsWorkingDocumentsWorkDocument i, SourceDocumentsWorkingDocumentsWorkDocumentLine l)
        {
            return 1;
        }

        private void OpenMovementInExcel(SourceDocumentsWorkingDocumentsWorkDocument doc, SourceDocumentsWorkingDocumentsWorkDocumentLine[] lines)
        {
            if (doc != null && doc.DocumentStatus != null && doc.DocumentTotals != null)
            {
                DataTable dtinvoice = new DataTable("WorkDocument");
                dtinvoice.Columns.Add("No", typeof(string));
                dtinvoice.Columns.Add("Estado", typeof(string));
                dtinvoice.Columns.Add("Data documento", typeof(DateTime));
                dtinvoice.Columns.Add("Data sistema", typeof(DateTime));
                dtinvoice.Columns.Add("Total s/ IVA", typeof(decimal));
                dtinvoice.Columns.Add("Total", typeof(decimal));
                dtinvoice.Columns.Add("Total imposto", typeof(decimal));
                dtinvoice.Columns.Add("Cliente", typeof(string));
                dtinvoice.Columns.Add("Periodo", typeof(int));
                dtinvoice.Columns.Add("Código CAE", typeof(string));
                dtinvoice.Columns.Add("Data Estado", typeof(DateTime));
                dtinvoice.Columns.Add("Motivo", typeof(string));
                dtinvoice.Columns.Add("Origem", typeof(string));
                dtinvoice.Columns.Add("Utilizador (responsável pelo estado)", typeof(string));
                dtinvoice.Columns.Add("Utilizador (gerou o documento)", typeof(string));
                dtinvoice.Columns.Add("Hash", typeof(string));
                dtinvoice.Columns.Add("Hash Test", typeof(string));
                dtinvoice.Columns.Add("Hash Control", typeof(string));

                dtinvoice.Rows.Add(
                    doc.DocumentNumber,
                    doc.DocumentStatus.WorkStatus.ToString(),
                    doc.WorkDate,
                    doc.SystemEntryDate,
                    doc.DocumentTotals.NetTotal,
                    doc.DocumentTotals.GrossTotal,
                    doc.DocumentTotals.TaxPayable,
                    doc.CustomerID,
                    Int32.Parse(doc.Period),
                    doc.EACCode,
                    doc.DocumentStatus.WorkStatusDate,
                    doc.DocumentStatus.Reason,
                    doc.DocumentStatus.SourceBilling,
                    doc.DocumentStatus.SourceID,
                    doc.SourceID,
                    doc.Hash,
                    doc.HashTest,
                    doc.HashControl);

                ExcelPackage pck = new ExcelPackage();
                var wsEnum = pck.Workbook.Worksheets.Add("SAFT Work document");
                wsEnum.Cells["C2"].Style.Numberformat.Format = "yyyy-MM-dd";
                wsEnum.Cells["D2"].Style.Numberformat.Format = "yyyy-MM-dd hh:mm:ss";
                wsEnum.Cells["K2"].Style.Numberformat.Format = "yyyy-MM-dd hh:mm:ss";

                wsEnum.Cells["E2"].Style.Numberformat.Format = @"#,##0.00";
                wsEnum.Cells["F2"].Style.Numberformat.Format = @"#,##0.00";
                wsEnum.Cells["G2"].Style.Numberformat.Format = @"#,##0.00";
                //Load the collection starting from cell A1...
                wsEnum.Cells["A1"].LoadFromDataTable(dtinvoice, true, TableStyles.Medium9);
                wsEnum.Cells[wsEnum.Dimension.Address].AutoFitColumns();

                if (lines != null)
                {
                    DataTable dtlines = new DataTable("WorkDocumentLines");

                    dtlines.Columns.Add("Nº linha", typeof(int));
                    dtlines.Columns.Add("Código produto", typeof(string));
                    dtlines.Columns.Add("Descrição produto", typeof(string));
                    dtlines.Columns.Add("Quantidade", typeof(decimal));
                    dtlines.Columns.Add("Preço unitário", typeof(decimal));
                    dtlines.Columns.Add("Valor", typeof(decimal));
                    dtlines.Columns.Add("Desconto", typeof(decimal));
                    dtlines.Columns.Add("Tipo operação", typeof(string));
                    dtlines.Columns.Add("Imposto", typeof(decimal));
                    dtlines.Columns.Add("Isenção imposto", typeof(string));
                    dtlines.Columns.Add("Unidade medida", typeof(string));
                    dtlines.Columns.Add("Data", typeof(DateTime));
                    dtlines.Columns.Add("Descrição", typeof(string));
                    dtlines.Columns.Add("DocNumber", typeof(string));

                    foreach (var line in lines)
                    {
                        dtlines.Rows.Add(
                            line.LineNumber,
                            line.ProductCode,
                            line.ProductDescription,
                            line.Quantity,
                            line.UnitPrice,
                            line.Item,
                            line.SettlementAmount,
                            line.ItemElementName.ToString(),
                            line.Tax.Item,
                            line.TaxExemptionReason,
                            line.UnitOfMeasure,
                            line.TaxPointDate,
                            line.Description,
                            line.DocNo);
                    }

                    var wsEnumLines = pck.Workbook.Worksheets.Add("SAFT Work document lines");
                    wsEnumLines.Cells[string.Format("L2:L{0}", lines.Length + 1)].Style.Numberformat.Format = "yyyy-MM-dd hh:mm:ss";

                    wsEnumLines.Cells[string.Format("D2:D{0}", lines.Length + 1)].Style.Numberformat.Format = @"#,##0.00";
                    wsEnumLines.Cells[string.Format("E2:E{0}", lines.Length + 1)].Style.Numberformat.Format = @"#,##0.00";
                    wsEnumLines.Cells[string.Format("F2:F{0}", lines.Length + 1)].Style.Numberformat.Format = @"#,##0.00";
                    wsEnumLines.Cells[string.Format("G2:G{0}", lines.Length + 1)].Style.Numberformat.Format = @"#,##0.00";

                    wsEnumLines.Cells[string.Format("D{0}", lines.Length + 2)].Formula = string.Format("SUM(D2:D{0})", lines.Length + 1);
                    wsEnumLines.Cells[string.Format("E{0}", lines.Length + 2)].Formula = string.Format("SUM(E2:E{0})", lines.Length + 1);
                    wsEnumLines.Cells[string.Format("F{0}", lines.Length + 2)].Formula = string.Format("SUM(F2:F{0})", lines.Length + 1);
                    wsEnumLines.Cells[string.Format("G{0}", lines.Length + 2)].Formula = string.Format("SUM(G2:G{0})", lines.Length + 1);

                    //Load the collection starting from cell A1...
                    wsEnumLines.Cells["A1"].LoadFromDataTable(dtlines, true, TableStyles.Medium9);
                    wsEnumLines.Cells[wsEnum.Dimension.Address].AutoFitColumns();
                }

                //...and save
                var fi = new FileInfo(Path.GetTempPath() + Path.GetRandomFileName() + ".xlsx");

                pck.SaveAs(fi);

                Process.Start(fi.FullName);
            }
        }
    }
}
